#include "DEBUG.C"
#include <CH559.H>
#include <string.h>
#include "USB_Section.h"


#define Ep0BUFFER_SIZE 8
#define Ep1BUFFER_SIZE 64
#define Ep2BUFFER_SIZE 64
UINT8X	Ep0Buffer[Ep0BUFFER_SIZE] _at_ 0x0000;                                //�˵�0 OUT&IN��������������ż��ַ
UINT8X	Ep2Buffer[2*Ep2BUFFER_SIZE] _at_ 0x0008;                              //�˵�2 IN&OUT������,������ż��ַ
UINT8X  Ep1Buffer[Ep1BUFFER_SIZE] _at_ 0x00a0;      
const UINT8 LangDes[]={0x04,0x03,0x09,0x04};           //ÓïÑÔÃèÊö·û                          
struct _line_coding line_coding;

UINT8 USB_DATA_LEN;

#ifdef USE_MY_UIF_TRANSFER
static UINT8 ReqType, ReqCode,ReqValue,Setuplen,len;
#else if
#define UsbSetupBuf     ((PUSB_SETUP_REQ)Ep0Buffer)
UINT8 RecBuf[64];
UINT8 SetReqtp,SetupReq,SetupLen,UsbConfig,Flag;
UINT8   num = 0;
UINT8   LEN = 0;
UINT8C DevDesc[18]={0x12,0x01,0x10,0x01,0xff,0x00,0x02,0x08,                   //Éè±¸ÃèÊö·û
                    0x86,0x1a,0x23,0x55,0x04,0x03,0x00,0x00,
                    0x00,0x01};
UINT8C CfgDesc[39]={0x09,0x02,0x27,0x00,0x01,0x01,0x00,0x80,0xf0,            //ÅäÖÃÃèÊö·û£¬½Ó¿ÚÃèÊö·û,¶ËµãÃèÊö·û
	                  0x09,0x04,0x00,0x00,0x03,0xff,0x01,0x02,0x00,           
                    0x07,0x05,0x82,0x02,0x20,0x00,0x00,                      //ÅúÁ¿ÉÏ´«¶Ëµã
		                0x07,0x05,0x02,0x02,0x20,0x00,0x00,                      //ÅúÁ¿ÏÂ´«¶Ëµã      
			              0x07,0x05,0x81,0x03,0x08,0x00,0x01};                     //ÖÐ¶ÏÉÏ´«¶Ëµã
UINT8C DataBuf[26]={0x30,0x00,0xc3,0x00,0xff,0xec,0x9f,0xec,0xff,0xec,0xdf,0xec,
                    0xdf,0xec,0xdf,0xec,0x9f,0xec,0x9f,0xec,0x9f,0xec,0x9f,0xec,
                    0xff,0xec};
#endif
static UINT8 *pDescr;

void USBDeviceCfg()
{
	USB_CTRL = 0x00;                                                           //���USB���ƼĴ���
    USB_CTRL &= ~bUC_HOST_MODE;                                                //��λΪѡ���豸ģʽ
    USB_CTRL |=  bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN;					           //USB�豸���ڲ�����ʹ��,���ж��ڼ��жϱ�־δ���ǰ�Զ�����NAK
    USB_DEV_AD = 0x00;                                                         //�豸��ַ��ʼ��

    UDEV_CTRL &= ~bUD_RECV_DIS;                                                //ʹ�ܽ�����
//  USB_CTRL |= bUC_LOW_SPEED;    
//  UDEV_CTRL |= bUD_LOW_SPEED;                                                //ѡ�����1.5Mģʽ

    USB_CTRL &= ~bUC_LOW_SPEED;
    UDEV_CTRL &= ~bUD_LOW_SPEED;                                               //ѡ��ȫ��12Mģʽ��Ĭ�Ϸ�ʽ

    UDEV_CTRL |= bUD_DP_PD_DIS | bUD_DM_PD_DIS;                                //��ֹDM��DP��������
    UDEV_CTRL |= bUD_PORT_EN;  
}

void USBIntCfg(void)
{
	USB_INT_EN |= bUIE_SUSPEND;                                                //ʹ���豸�����ж�
    USB_INT_EN |= bUIE_TRANSFER;                                               //ʹ��USB��������ж�
    USB_INT_EN |= bUIE_BUS_RST;                                                //ʹ���豸ģʽUSB���߸�λ�ж�
    USB_INT_FG |= 0x1F;                                                        //���жϱ�־
    IE_USB = 1;                                                                //ʹ��USB�ж�
    EA = 1; 																                                   
}

void USBEndPointCfg(void)
{
	UEP2_DMA = Ep2Buffer;
	UEP2_3_MOD |= bUEP2_TX_EN;
	UEP2_3_MOD |= bUEP2_RX_EN;
	UEP2_3_MOD &= ~(bUEP2_BUF_MOD);
	UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
	
	UEP1_DMA = Ep1Buffer;
	UEP4_1_MOD |= bUEP1_TX_EN;
	UEP4_1_MOD &= ~bUEP1_BUF_MOD;
	UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
	
	UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN);
	
	UEP0_DMA = Ep0Buffer;
	UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
	
}

void USB_CDC_Serial_SetLineCoding(struct _line_coding * attr)
{
	*(unsigned int*)(&(attr->dwDTERate0)) = 115200;
	attr->bParityType = 0x00;
	attr->bCharFormat = 0x00;
	attr->bDataBits = 8;
}

void main(void)
{
	USB_CDC_Serial_SetLineCoding(&line_coding);
	mDelaymS(30);
	
	mInitSTDIO();

	USBDeviceCfg();
	USBEndPointCfg();
	USBIntCfg();
	UEP0_T_LEN = 0;
	UEP1_T_LEN = 0;
	UEP2_T_LEN = 0;
	
	while(1);
}

void USBDeivceInterrupt(void) interrupt INT_NO_USB using 1
{
	UINT8 len;
//	CH559UART0SendByte('S');
//	CH559UART0SendByte('\n');
#ifdef USE_MY_UIF_TRANSFER
	if(UIF_TRANSFER)
	{
		switch(USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
		{
			case UIS_TOKEN_OUT | 2:
				//COM_Data from HOST
				USB_DATA_LEN = USB_RX_LEN;
				//Recv Handler
				break;
			case UIS_TOKEN_IN | 2:
				//HOST Request COM Data
				UEP2_T_LEN = 0; // Handle here,Defaults return 0 for no data;
				break;
			case UIS_TOKEN_SETUP | 0:
				len = USB_RX_LEN;
				if(len == sizeof(USB_SETUP_REQ))
				{
					ReqType = USB_SETUP_PACKET->bRequestType;
					ReqCode = USB_SETUP_PACKET->bRequest;
					Setuplen = USB_SETUP_PACKET->wLengthL;
					len = 0;

					switch(ReqType)
					{
						case 0x80:
							switch(ReqCode)
							{
								case USB_GET_DESCRIPTOR:
									switch(ReqValue)
									{
										case USB_DESCR_TYP_DEVICE:
											pDescr = usb_device_descriptor;
											len = sizeof(usb_device_descriptor);
										break;
										
										case USB_DESCR_TYP_CONFIG:
											pDescr = usb_configuration_descriptor;
											len = sizeof(usb_configuration_descriptor);
										break;

										default:
											// requested descriptor invalid
											len = 0xff;
										break;
									}
									if(Setuplen >= len)
										Setuplen = len;
									if(Setuplen > 8)
										len = 8;
									else
										len = Setuplen;
									memcpy(Ep0Buffer, pDescr, len);
									Setuplen-=len;
									pDescr+=len;
								break;
								case USB_GET_CONFIGURATION:
									Ep0Buffer[0] = usb_config;
									len = 1;
								break;

								default:
									//Unsupport
									len = 0xff;
								break;
							}
							if(len == 0xff)
							{
								ReqCode = 0xff;
								UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;
							}
							else if(len <= 8)
							{
								UEP0_T_LEN = len;
								UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
							}
							else
							{
								UEP0_T_LEN = 0;
								UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; 		
							}
						break;
						case 0x00:
							switch(ReqCode) 
							{
								case USB_SET_ADDRESS:
									USB_DEV_AD = USB_SETUP_PACKET->wValueL;
								break;
								case USB_SET_CONFIGURATION:
									usb_config = USB_SETUP_PACKET->wValueL;
								break;
								default:
									len = 0xff;
								break;
							}
						break;

						default:
							len = 0xff;
						break;
					}
					
				}
				else
				{
					len = 0xff;
				}
			break;
			case UIS_TOKEN_IN|0:
				switch(ReqCode)
				{
					case USB_GET_DESCRIPTOR:
						if(Setuplen > 8)
						{
							len = 8;
						}
						else
						{
							len = Setuplen;
						}
						memcpy(Ep0Buffer,pDescr,len);
						Setuplen -= len;
						pDescr+=len;
						UEP0_T_LEN = len;
						UEP0_CTRL ^= bUEP_T_TOG;
					break;
					case USB_SET_ADDRESS:
						// USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
						// UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
					break;
					default:
						UEP0_T_LEN = 0;                                                    
						UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
					break;
				}
			break;
			case UIS_TOKEN_OUT|0:
				len = USB_RX_LEN;
				UEP0_T_LEN = 0;                                   
				UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;   
			break;

			case UIS_TOKEN_IN | 1:
				UEP1_T_LEN = 0;
				UEP1_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; 
			break;
		}
		UIF_TRANSFER = 0;
	}
#else if

	if(UIF_TRANSFER)                                                               //USB´«ÊäÍê³É±êÖ¾
	{
		switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
		{
				case UIS_TOKEN_OUT | 2:                                                   //endpoint 2# ÖÐ¶ÏÏÂ´«					 
					LEN = USB_RX_LEN; 
				break;
			case UIS_TOKEN_IN | 2:                                                    //endpoint 2# ÖÐ¶ÏÉÏ´«
				UEP2_T_LEN = 0;	                                                     //Ô¤Ê¹ÓÃ·¢ËÍ³¤¶ÈÒ»¶¨ÒªÇå¿Õ						 
				UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_R_RES | UEP_R_RES_ACK;                    //Ä¬ÈÏÓ¦´ðACK					 
				UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;            //Ä¬ÈÏÓ¦´ðNAK
			break;
			case UIS_TOKEN_SETUP | 0:                                                  //SETUPÊÂÎñ
				len = USB_RX_LEN;
				if(len == (sizeof(USB_SETUP_REQ)))
				{   
					SetReqtp = UsbSetupBuf->bRequestType;
					SetupLen = UsbSetupBuf->wLengthL;
					len = 0;                                                           //Ä¬ÈÏÎª³É¹¦²¢ÇÒÉÏ´«0³¤¶È,±ê×¼ÇëÇó                                                              
					SetupReq = UsbSetupBuf->bRequest;
#ifndef USE_MY_UIF_TRANSFER
					if(SetReqtp == 0xc0)
					{
						Ep0Buffer[0] = DataBuf[num];
						Ep0Buffer[1] = DataBuf[num+1];
						len = 2;
						if(num<24)
						{	
							num += 2;
							}
							else
							{
								num = 24;
							}
					}
					else if(SetReqtp == 0x40)
					{
							len = 9;                                                        //±£Ö¤×´Ì¬½×¶Î£¬ÕâÀïÖ»Òª±È8´ó£¬ÇÒ²»µÈÓÚ0xff¼´¿É
					}
					else if((SetReqtp & 0x60) == 0x00) // Standard Request
					{ 
#endif
						switch(SetupReq)                                                //ÇëÇóÂë
						{
							case USB_GET_DESCRIPTOR:
								switch(UsbSetupBuf->wValueH)
								{
									case 1:	                                            //Éè±¸ÃèÊö·û
#ifdef USE_MY_UIS_TRANSFER
										pDescr = usb_device_descriptor;                                //°ÑÉè±¸ÃèÊö·ûËÍµ½Òª·¢ËÍµÄ»º³åÇø
										len = sizeof(usb_device_descriptor);								       
#else if
										// pDescr = DevDesc;
										// len = sizeof(DevDesc);
										pDescr = usb_device_descriptor;
										len = sizeof(usb_device_descriptor);
#endif
									break;	 
									case 2:									                            //ÅäÖÃÃèÊö·û
#ifdef USE_MY_UIF_TRANSFER
										pDescr = usb_configuration_descriptor;                                //°ÑÅäÖÃÃèÊö·ûËÍµ½Òª·¢ËÍµÄ»º³åÇø
										len = sizeof(usb_configuration_descriptor);
#else if
										// pDescr = CfgDesc;
										// len = sizeof(CfgDesc);
										pDescr = usb_configuration_descriptor;
										len = sizeof(usb_configuration_descriptor);
#endif 
									break;	
									case 3:
										if(UsbSetupBuf->wValueL == 0)
										{
											pDescr = LangDes;                                          
											len = sizeof(LangDes);								
										}
									default:
										len = 0xff;                                      //²»Ö§³ÖµÄÃüÁî»òÕß³ö´í
									break;
								}
								if ( SetupLen > len ) SetupLen = len;                  //ÏÞÖÆ×Ü³¤¶È
								len = SetupLen >= 8 ? 8 : SetupLen;                    //±¾´Î´«Êä³¤¶È
								memcpy(Ep0Buffer,pDescr,len);                          //¼ÓÔØÉÏ´«Êý¾Ý
								SetupLen -= len;
								pDescr += len;
							break;			 
							case USB_GET_STATUS:
								Ep0Buffer[0] = 0x01;
								Ep0Buffer[1] = 0x00;
								len = 2;
							break;
							case USB_SET_ADDRESS:
								SetupLen = UsbSetupBuf->wValueL;                       //ÔÝ´æUSBÉè±¸µØÖ·
								break;
							case USB_GET_CONFIGURATION:
								Ep0Buffer[0] = UsbConfig;
								if ( SetupLen >= 1 ) len = 1;
								break;
							case USB_SET_CONFIGURATION:
								UsbConfig = UsbSetupBuf->wValueL;
								break;
							default:
								len = 0xff;                                            //²Ù×÷Ê§°Ü
								break;    
						}
#ifndef USE_MY_UIF_TRANSFER
					}
#endif
				else if((SetReqtp & 0x60) == 0x20) // Class Request
				{
					switch(SetupReq)
					{
						case USB_SET_LINE_CODING:
						break;
						case USB_GET_LINE_CODING:
							len = sizeof(struct _line_coding);
							pDescr = (UINT8*)&line_coding;
							len = len = SetupLen >= DEFAULT_ENDP0_SIZE ? DEFAULT_ENDP0_SIZE : SetupLen;
							memcpy(Ep0Buffer,pDescr,len); 
							SetupLen -= len;
							pDescr += len;
						break;
						case USB_SET_CONTROL_LINE_STATE:
						break;
						default:
							len = 0xff; 
						break;
					}
				}
				else
				{
					len = 0xff;                                                     //°ü³¤¶È´íÎó
				}
			}
				if(len == 0xff)
				{
					SetupReq = 0xFF;
					UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL				     
				}
				else if(len <= 8)                                                         //ÉÏ´«Êý¾Ý»òÕß×´Ì¬½×¶Î·µ»Ø0³¤¶È°ü
				{
					UEP0_T_LEN = len;
					UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;  //Ä¬ÈÏÊý¾Ý°üÊÇDATA1£¬·µ»ØÓ¦´ðACK
				}
				else
				{
					UEP0_T_LEN = 0;                                                       //ËäÈ»ÉÐÎ´µ½×´Ì¬½×¶Î£¬µ«ÊÇÌáÇ°Ô¤ÖÃÉÏ´«0³¤¶ÈÊý¾Ý°üÒÔ·ÀÖ÷»úÌáÇ°½øÈë×´Ì¬½×¶Î
					UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;  //Ä¬ÈÏÊý¾Ý°üÊÇDATA1,·µ»ØÓ¦´ðACK				     
				}
				break;
			case UIS_TOKEN_IN | 0:                                                         //endpoint0 IN
				switch(SetupReq)
				{
					case USB_GET_DESCRIPTOR:
						len = SetupLen >= 8 ? 8 : SetupLen;                               //±¾´Î´«Êä³¤¶È
						memcpy( Ep0Buffer, pDescr, len );                                 //¼ÓÔØÉÏ´«Êý¾Ý
						SetupLen -= len;
						pDescr += len;
						UEP0_T_LEN = len;
						UEP0_CTRL ^= bUEP_T_TOG;                                          //Í¬²½±êÖ¾Î»·­×ª
					break;
					case USB_SET_ADDRESS:
						USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
						UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
					break;
					case USB_GET_STATUS:
						UEP0_T_LEN = len;
						UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;
						// UEP0_CTRL ^= bUEP_T_TOG;
					break;
					case USB_GET_LINE_CODING:
						UEP0_T_LEN = len;
						UEP0_CTRL ^= bUEP_T_TOG;
					break;
					default:
						UEP0_T_LEN = 0;                                                    //×´Ì¬½×¶ÎÍê³ÉÖÐ¶Ï»òÕßÊÇÇ¿ÖÆÉÏ´«0³¤¶ÈÊý¾Ý°ü½áÊø¿ØÖÆ´«Êä
						UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
					break;
				}
			break;
			case UIS_TOKEN_OUT | 0:                                                 // endpoint0 OUT
				switch(SetupReq)
				{
					case USB_GET_LINE_CODING:
						if(U_TOG_OK)
						{
							memcpy(&line_coding, Ep0Buffer, USB_RX_LEN);
							UEP0_T_LEN = 0;
							UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;
						}
					break;
					default:
						UEP0_T_LEN = 0;
						UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_ACK;
					break;
				}
				UEP0_T_LEN = 0;                                                    //ËäÈ»ÉÐÎ´µ½×´Ì¬½×¶Î£¬µ«ÊÇÌáÇ°Ô¤ÖÃÉÏ´«0³¤¶ÈÊý¾Ý°üÒÔ·ÀÖ÷»úÌáÇ°½øÈë×´Ì¬½×¶Î
				UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;                         //Ä¬ÈÏÊý¾Ý°üÊÇDATA0,·µ»ØÓ¦´ðACK									
			break;
			default:
			break;
		}
		UIF_TRANSFER = 0;                                                        //Ð´0Çå¿ÕÖÐ¶Ï  
	}
#endif
	if(UIF_BUS_RST)                                                              //Éè±¸Ä£Ê½USB×ÜÏß¸´Î»ÖÐ¶Ï
    {
			USB_DEV_AD = 0x00;
			UIF_SUSPEND = 0;
			UIF_TRANSFER = 0;
			UIF_BUS_RST = 0;                                                           //ÇåÖÐ¶Ï±êÖ¾
    }
	if (UIF_SUSPEND) 
		{                                                                            //USB×ÜÏß¹ÒÆð/»½ÐÑÍê³É
			UIF_SUSPEND = 0;
			if ( USB_MIS_ST & bUMS_SUSPEND ) 
			{                                                                          //¹ÒÆð
				while ( XBUS_AUX);                                          //µÈ´ý·¢ËÍÍê³É
				SAFE_MOD = 0x55;
				SAFE_MOD = 0xAA;
				WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO;                                  //USB»òÕßRXD0ÓÐÐÅºÅÊ±¿É±»»½ÐÑ
				PCON |= PD;                                                              //Ë¯Ãß
				SAFE_MOD = 0x55;
				SAFE_MOD = 0xAA;
				WAKE_CTRL = 0x00;
			}
    } 
	else 
	{                                                                             //ÒâÍâµÄÖÐ¶Ï,²»¿ÉÄÜ·¢ÉúµÄÇé¿ö
		  USB_INT_FG = 0x00;                                                          //ÇåÖÐ¶Ï±êÖ¾
	}   
}
